package com.landliu.idea.plugin.cgpt.service.impl;

import com.google.common.base.CaseFormat;
import com.landliu.idea.plugin.cgpt.common.utils.JavaType;
import com.landliu.idea.plugin.cgpt.model.po.*;
import com.landliu.idea.plugin.cgpt.model.vo.CodeGenContextVO;
import com.landliu.idea.plugin.cgpt.service.ProjectGeneratorService;

import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;

import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

public class ProjectGeneratorServiceImpl implements ProjectGeneratorService {

    private static final String ENCODING = "UTF-8";

    private static final FreemarkerConfiguration freemarker = new FreemarkerConfiguration("/template");

    static class FreemarkerConfiguration extends Configuration{

        public FreemarkerConfiguration(String basePackagePath) {
            super(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
            setDefaultEncoding(ENCODING);
            setClassForTemplateLoading(getClass(), basePackagePath);
        }

    }

    public void writeFile(Project project, String packageName, String name, String ftl, Object dataModel) {
        VirtualFile virtualFile;
        try {
            virtualFile = createPackageDir(packageName).createChildData(project, name);
            StringWriter stringWriter = new StringWriter();
            Template template = freemarker.getTemplate(ftl, ENCODING);
            template.process(dataModel, stringWriter);
            virtualFile.setBinaryContent(stringWriter.toString().getBytes(StandardCharsets.UTF_8));
        } catch (IOException | TemplateException e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    public static VirtualFile createPackageDir(String packageName) {
        String path = FileUtil.toSystemIndependentName(StringUtil.replace(packageName, ".", "/"));
        new File(path).mkdirs();
        return LocalFileSystem.getInstance().refreshAndFindFileByPath(path);
    }
    @Override
    public void generation(Project project, CodeGenContextVO codeGenContextVO) {

        String basePath = project.getBasePath() + "/src/main/java";
        File baseFile = new File(basePath);
        if(!baseFile.exists()){
            baseFile.mkdirs();
        }

        List<Table> tables = codeGenContextVO.getTables();
        for (Table table : tables) {
            List<Column> columns = table.getColumns();
            List<Field> fields = new ArrayList<>();

            for (Column column : columns) {
                Field field = new Field(column.getComment(), JavaType.convertType(column.getType()), column.getName());
                field.setId(column.isId());
                fields.add(field);
            }

            // 生成PO
            Model model = new Model(table.getComment(), basePath + "/" +codeGenContextVO.getModelPackage() + CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, table.getName()), table.getName(), fields);
            writeFile(project, basePath + "/" + codeGenContextVO.getModelPackage(), model.getSimpleName() + ".java", "model.ftl", model);

            // 生成DAO
            Dao dao = new Dao(table.getComment(), basePath + "/" +codeGenContextVO.getMapperPackage() + CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, table.getName()) + "Mapper", model);
            writeFile(project, basePath + "/" + codeGenContextVO.getMapperPackage(), dao.getSimpleName() + ".java", "dao.ftl", dao);

            // 生成Mapper
            writeFile(project, basePath + "/" + codeGenContextVO.getMapperPackage(), dao.getModel().getSimpleName() + "Mapper.xml", "mapper.ftl", dao);

            //Service
            Business business = new Business(table.getComment(),basePath + "/" +codeGenContextVO.getServicePackage() + CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, table.getName()) + "Service", model);

            writeFile(project, basePath + "/" + codeGenContextVO.getServicePackage(), business.getSimpleName() + ".java", "service.ftl", business);

            //ServiceImpl
            writeFile(project, basePath + "/" + codeGenContextVO.getServicePackage()+ "/impl", business.getSimpleName() + "Impl.java", "service_impl.ftl", business);
        }
    }
}
